//=============================================================================
/**
 * @file	g3d_anime_manager.c
 * @brief	3Dアニメーションマネージャ関連処理
 * @author	Nozomu Saito
 *
 */
//=============================================================================
#include "common.h"

#include "g3d_anime_manager.h"

typedef enum{
	STATE_END,	//終了
	STATE_MOVE,	//稼動中
}ANIME_STATE;

typedef enum{
	DATA_INVALID,
	DATA_VALID,
}DATA_VAL_STATE;

typedef struct G3D_ANIME_DATA_tag{
	NNSG3dAnmObj* AnmObjPtr;
	void *Mem;
	int LoopMax;
	BOOL Stop;
	BOOL Reverse;

	DATA_VAL_STATE Valid;
	int LoopCount;
	ANIME_STATE State;

}G3D_ANIME_DATA;

typedef struct G3D_ANIME_MANAGER_tag{
	NNSFndAllocator AnimeAllocator;
	G3D_ANIME_DATA *AnimeData;
	G3D_ANIME_DATA **AnimeDataStack;
	struct G3D_ANIME_MANAGER_tag *Next;
	CSTM_SETUP_FUNC CstmSetupFunc;
	u16 AnimeMax;					//アニメ最大管理数
	u16 StackNum;					//スタック数(現在管理数)
}G3D_ANIME_MANAGER;

typedef struct G3D_ANIME_MANAGER_LIST_tag{
	G3D_ANIME_MANAGER *Item;
	G3D_ANIME_MANAGER *Top;
	G3D_ANIME_MANAGER *Bottom;
	int Count;
}G3D_ANIME_MANAGER_LIST;

static void ChangeFrame(G3D_ANM_DATA_PTR	outAnimeData);
static BOOL IsLastFrame(G3D_ANM_DATA_PTR	inAnimeData);

//==============================================================================
/**
 * マネージャリスト初期化
 *
 * @param   inHeapID	ヒープＩＤ
 *
 * @retval  ptr			アニメマネージャポインタ
 */
//==============================================================================
G3D_ANM_MNG_LST_PTR G3dAnime_InitManagerList( const int inHeapID )
{
	int i;
	int size;
	G3D_ANM_MNG_LST_PTR ptr;
	ptr = sys_AllocMemory(inHeapID, sizeof(G3D_ANIME_MANAGER_LIST));
	ptr->Count = 0;
	ptr->Item = NULL;
	ptr->Top = NULL;
	ptr->Bottom = NULL;
	return ptr;
}

//==============================================================================
/**
 * マネージャ作成
 *
 * @param	pMngLstPtr	 マネージャリストポインタ
 * @param   inHeapID	ヒープＩＤ
 * @param	inAnimeNum	マネージャが管理するアニメ総数
 *
 * @retval  ptr			アニメマネージャポインタ
 */
//==============================================================================
G3D_ANM_MNG_PTR G3dAnime_CreateManager( G3D_ANM_MNG_LST_PTR pMngLstPtr, const int inHeapID, const int inAnimeNum )
{
	int i;
	int size;
	G3D_ANM_MNG_PTR ptr;
	ptr = sys_AllocMemory(inHeapID, sizeof(G3D_ANIME_MANAGER));
	ptr->StackNum = 0;
	ptr->AnimeMax = inAnimeNum;
	ptr->CstmSetupFunc = NULL;

	//アニメアロケータ
	sys_InitAllocator(&ptr->AnimeAllocator,inHeapID,4);

	size = sizeof(G3D_ANIME_DATA)*inAnimeNum;
	ptr->AnimeData = sys_AllocMemory(inHeapID,size);
	MI_CpuClearFast(ptr->AnimeData,size);

	ptr->AnimeDataStack = (G3D_ANIME_DATA	**)sys_AllocMemory(inHeapID,sizeof(int)*inAnimeNum);
	for( i=0; i<inAnimeNum; i++ )
	{
		ptr->AnimeData[i].Valid = DATA_INVALID;
		ptr->AnimeData[i].Mem = NULL;
		ptr->AnimeData[i].AnmObjPtr = NULL;
		ptr->AnimeDataStack[i] = &(ptr->AnimeData[i]);
	}
	ptr->Next = NULL;

	//リストに追加
	if (pMngLstPtr->Top == NULL){	//リストが空
		pMngLstPtr->Top = ptr;
		pMngLstPtr->Bottom = ptr;
		pMngLstPtr->Item = ptr;
	}else{	//すでにリストに追加されている項目あり
		pMngLstPtr->Bottom->Next = ptr;
		pMngLstPtr->Bottom = ptr;
	}
	pMngLstPtr->Count++;

	return ptr;
}

//==============================================================================
/**
 * 終了
 *
 * @param   pMngLstPtr	アニメマネージャポインタ
 *
 * @retval  none
 */
//==============================================================================
void G3dAnime_End( G3D_ANM_MNG_LST_PTR pMngLstPtr  )
{
	int i,j;
	G3D_ANM_DATA_PTR	anime_data;
	G3D_ANM_MNG_PTR		mng_ptr;
	if (pMngLstPtr == NULL) return;
	mng_ptr = pMngLstPtr->Top;
	if (mng_ptr == NULL){
		sys_FreeMemoryEz( pMngLstPtr );
		return;
	}

	for (i=0;i<pMngLstPtr->Count;i++){
		for(j=0;j<mng_ptr->AnimeMax;j++){
			//エントリしているアニメデータを解放
			anime_data = &(mng_ptr->AnimeData[j]);

			//アニメは有効かどうか
			if (anime_data->Valid == DATA_VALID){
				//アニメ解放
				G3dAnimeData_FreeAnimeObj(mng_ptr, anime_data);
				//返却
				G3dAnime_PushAnmData(mng_ptr, anime_data);
			}
		}// end for
		sys_FreeMemoryEz(mng_ptr->AnimeData);
		sys_FreeMemoryEz(mng_ptr->AnimeDataStack);
		{
			G3D_ANM_MNG_PTR del_ptr;
			del_ptr = mng_ptr;
			mng_ptr = mng_ptr->Next;
			sys_FreeMemoryEz( del_ptr );
		}
	}// end for
	sys_FreeMemoryEz( pMngLstPtr );
}


//==============================================================================
/**
 * アニメデータ取得
 * この関数の外で、リソース確保と、アニメＯＢＪ
 *
 * @param   pMngPtr		マネージャポインタ
 *
 * @retval  ptr			アニメマネージャポインタ
 */
//==============================================================================
G3D_ANM_DATA_PTR G3dAnime_PopAnmData( G3D_ANM_MNG_PTR pMngPtr )
{
	G3D_ANM_DATA_PTR anime_data;
	if (pMngPtr->StackNum >= pMngPtr->AnimeMax){
		GF_ASSERT(0);
		return NULL;
	}
	anime_data = pMngPtr->AnimeDataStack[pMngPtr->StackNum++];
	return anime_data;
}

//==============================================================================
/**
 * アニメデータの返却
 *
 * @param   pMngPtr		マネージャポインタ
 * @param   pAnmDatar	アニメデータポインタ
 *
 * @retval  none
 */
//==============================================================================
void G3dAnime_PushAnmData(G3D_ANM_MNG_PTR pMngPtr, G3D_ANM_DATA_PTR pAnmData)
{
	if (pMngPtr->StackNum == 0){
		GF_ASSERT(0);
		return;
	}
	pMngPtr->StackNum--;
	if (pAnmData->Mem != NULL){
		sys_FreeMemoryEz(pAnmData->Mem);
	}
	pAnmData->AnmObjPtr = NULL;
	pAnmData->Valid = FALSE;
	pMngPtr->AnimeDataStack[pMngPtr->StackNum] = pAnmData;
}


//==============================================================================
/**
 * 現在のスタック数（管理数）を返す
 *
 * @param   pMngPtr		マネージャポインタ
 *
 * @retval  u16			スタック数
 */
//==============================================================================
const u16 G3dAnime_GetAnmStackNum(G3D_ANM_MNG_PTR pMngPtr)
{
	return pMngPtr->StackNum;
}

//==============================================================================
/**
 * メインループ
 *
 * @param   pMngPtr		マネージャポインタ
 *
 * @retval  none
 */
//==============================================================================
void G3dAnime_Main( G3D_ANM_MNG_LST_PTR pMngLstPtr )
{
	int i,j;
	G3D_ANM_DATA_PTR	anime_data;
	G3D_ANM_MNG_PTR		mng_ptr;

	if (pMngLstPtr == NULL) return;
	mng_ptr = pMngLstPtr->Top;
	if (mng_ptr == NULL) return;

	for (i=0;i<pMngLstPtr->Count;i++){
		for(j=0;j<mng_ptr->AnimeMax;j++){
			anime_data = &(mng_ptr->AnimeData[j]);
			//アニメは有効かどうか
			if (anime_data->Valid == DATA_VALID){
				//アニメーションが停止している、もしくはアニメが終了している場合は処理を飛ばす
				if ((anime_data->Stop == TRUE)||(anime_data->State == STATE_END)){
					continue;
				}

				ChangeFrame(anime_data);	//フレーム切り替え

				if ( anime_data->LoopMax != LOOP_INFINIT ){	//ループ指定回数あり
					if (IsLastFrame(anime_data)){			//最終フレームか？
						if (anime_data->LoopCount+1 >= anime_data->LoopMax){//最終指定ループ回数目か？
							//アニメ終了
							anime_data->State = STATE_END;
						}else{
							anime_data->LoopCount++;	//ループ数をインクリメント
						}
					}
				}
			}
		}// end for (mng_ptr->AnimeMax)
		mng_ptr = mng_ptr->Next;
	}// end for	(pMngLstPtr->Count)
}

//==============================================================================
/**
 * 動いているアニメをすべてストップ
 *
 * @param   pMngPtr		マネージャポインタ
 *
 * @retval  none
 */
//==============================================================================
void G3dAnime_StopAllAnm( G3D_ANM_MNG_LST_PTR pMngLstPtr )
{
	int i,j;
	G3D_ANM_DATA_PTR	anime_data;
	G3D_ANM_MNG_PTR		mng_ptr;

	if (pMngLstPtr == NULL) return;
	mng_ptr = pMngLstPtr->Top;
	if (mng_ptr == NULL) return;

	for (i=0;i<pMngLstPtr->Count;i++){
		for(j=0;j<mng_ptr->AnimeMax;j++){
			anime_data = &(mng_ptr->AnimeData[j]);
			//アニメは有効かどうか
			if (anime_data->Valid == DATA_VALID){
				//アニメが終了している場合は処理を飛ばす
				if ( anime_data->State == STATE_END ){
					continue;
				}
				anime_data->Stop = TRUE;
			}
		}// end for (mng_ptr->AnimeMax)
		mng_ptr = mng_ptr->Next;
	}// end for	(pMngLstPtr->Count)
}

//==============================================================================
/**
 * 動いているアニメをすべて開始フレームにする
 *
 * @param   pMngLstPtr		マネージャポインタ
 *
 * @retval  none
 */
//==============================================================================
void G3dAnime_SetStartFrameAll( G3D_ANM_MNG_LST_PTR pMngLstPtr )
{
	int i,j;
	G3D_ANM_DATA_PTR	anime_data;
	G3D_ANM_MNG_PTR		mng_ptr;

	if (pMngLstPtr == NULL) return;
	mng_ptr = pMngLstPtr->Top;
	if (mng_ptr == NULL) return;

	for (i=0;i<pMngLstPtr->Count;i++){
		for(j=0;j<mng_ptr->AnimeMax;j++){
			anime_data = &(mng_ptr->AnimeData[j]);
			//アニメは有効かどうか
			if (anime_data->Valid == DATA_VALID){
				//アニメが終了している場合は処理を飛ばす
				if ( anime_data->State == STATE_END ){
					continue;
				}
				G3dAnimeData_SetStartFrame(anime_data);
			}
		}// end for (mng_ptr->AnimeMax)
		mng_ptr = mng_ptr->Next;
	}// end for	(pMngLstPtr->Count)
}

//==============================================================================
/**
 * デフォルトセットアップ
 *
 * @param   pMngPtr		マネージャポインタ
 * @param	pAnmData	アニメデータポインタ
 * @param	mem			リソース
 * @param	pModel		リソースモデルポインタ
 * @param	pTex		テクスチャポインタ
 *
 * @retval  none
 */
//==============================================================================
void G3dAnime_SetupAnimeDefault(G3D_ANM_MNG_PTR pMngPtr,
								G3D_ANM_DATA_PTR pAnmData,
								void*	mem,
								NNSG3dResMdl*	pModel,
								NNSG3dResTex*	pTex)
{
    void *pAnmRes;

    pAnmRes = NNS_G3dGetAnmByIdx(mem, 0);
    GF_ASSERT(pAnmRes != NULL);

    // 必要量のメモリをアロケートする。イニシャライズは別途必要になる。
    pAnmData->AnmObjPtr = NNS_G3dAllocAnmObj(	&pMngPtr->AnimeAllocator, // 使用するアロケータを指定
												pAnmRes,    // アニメーションリソースを指定
												pModel);    // モデルリソースを指定
	GF_ASSERT(pAnmData->AnmObjPtr != NULL);

     // AnmObj を初期化する。ジョイントアニメーション以外も同様
    NNS_G3dAnmObjInit(pAnmData->AnmObjPtr, // アニメーションオブジェクトへのポインタ
			          pAnmRes, // アニメリソースへのポインタ
                      pModel,  // NNSG3dResMdlへのポインタ
                      pTex );  // NNSG3dResTexへのポインタ(テクスチャパターンアニメ以外ならばNULLでもよい)
	pAnmData->Mem = mem;
}

//==============================================================================
/**
 * カスタムセットアップ
 *
 * @param   pMngPtr		マネージャポインタ
 * @param	pAnmData	アニメデータポインタ
 * @param	pWork		カスタムセットアップ用のワーク
 *
 * @retval  none
 */
//==============================================================================
void G3dAnime_CustomSetup(G3D_ANM_MNG_PTR pMngPtr, G3D_ANM_DATA_PTR pAnmData, void *mem, G3D_ANM_CUSTOM_WORK_PTR pWork)
{
	if (pMngPtr->CstmSetupFunc){
		pMngPtr->CstmSetupFunc(&pMngPtr->AnimeAllocator, &pAnmData->AnmObjPtr, mem, pWork);
		pAnmData->Mem = mem;
	}
}

//==============================================================================
/**
 * カスタムセットアップ関数のセット
 *
 * @param  	pMngPtr		アニメマネージャポインタ
 * @param	pFunc 		カスタム関数
 *
 * @retval  none
 */
//==============================================================================
void G3dAnime_SetCustomFunc(G3D_ANM_MNG_PTR pMngPtr, CSTM_SETUP_FUNC pFunc)
{
	pMngPtr->CstmSetupFunc = pFunc;
}

//==============================================================================
/**
 * アニメデータにリソースメモリをセット
 * 外で確保されたメモリは、この関数にセットする。
 * セットしておくことで、終了時に、メモリの解放を行う
 *
 * @param   pAnmData	アニメデータポインタ
 * @param	mem			メモリ
 *
 * @retval  none
 */
//==============================================================================
void G3dAnimeData_SetAnmResMem(G3D_ANM_DATA_PTR pAnmData, void *mem)
{
	pAnmData->Mem = mem;
}

//==============================================================================
/**
 * アニメデータのエントリ
 * エントリすることで、初めてアニメループでアニメ更新が行われる
 *
 * @param   pAnmData	アニメデータポインタ
 * @param	inLoop		ループ数
 * @param	inStop		停止フラグ
 * @param	inReverse	逆再フラグ
 *
 * @retval  none
 */
//==============================================================================
void G3dAnimeData_Entry(G3D_ANM_DATA_PTR pAnmData,
						const int inLoop,
						const BOOL inStop,
						const BOOL inReverse )
{
	pAnmData->LoopCount = 0;
	pAnmData->State = STATE_MOVE;
	pAnmData->Valid = TRUE;

	pAnmData->LoopMax = inLoop;
	pAnmData->Stop = inStop;
	pAnmData->Reverse = inReverse;
}

//==============================================================================
/**
 * 開始アニメーションフレームセット
 *
 * @param	pAnmData	アニメーションデータへのポインタ
 *
 * @return	none
 */
//==============================================================================
void G3dAnimeData_SetStartFrame(G3D_ANM_DATA_PTR pAnmData)
{
	if (!pAnmData->Reverse){	//通常まわし
		pAnmData->AnmObjPtr->frame = 0;
	}else{						//逆まわし
		pAnmData->AnmObjPtr->frame = NNS_G3dAnmObjGetNumFrame(pAnmData->AnmObjPtr)-(FX32_ONE);
	}
}

//==============================================================================
/**
 * アニメOBJの解放
 *
 * @param   pMngPtr		マネージャポインタ
 * @param	pAnmData	アニメデータ
 *
 * @retval  none
 */
//==============================================================================
void G3dAnimeData_FreeAnimeObj(G3D_ANM_MNG_PTR pMngPtr, G3D_ANM_DATA_PTR pAnmData)
{
	NNS_G3dFreeAnmObj(	&pMngPtr->AnimeAllocator, pAnmData->AnmObjPtr);
}

//==============================================================================
/**
 * アニメの追加
 *
 * @param   pRenderObj		レンダーOBJ
 * @param	pAnmData		アニメデータ
 *
 * @retval  none
 */
//==============================================================================
void G3dAnimeData_Add(NNSG3dRenderObj *pRenderObj, G3D_ANM_DATA_PTR pAnmData)
{
#ifdef	DEBUG_ONLY_FOR_saitou
	{
		//テスト
		int idx;
		int i;
		NNSG3dResTexSRTAnm* srtAnm;
		const NNSG3dResMat* mat;
		mat = NNS_G3dGetMat(pRenderObj->resMdl);
		srtAnm = (NNSG3dResTexSRTAnm*)pAnmData->Mem;
///		OS_Printf("AnimeNum = %d\n",srtAnm->dict.numEntry);
		for (i = 0; i < srtAnm->dict.numEntry; ++i){
			const NNSG3dResName* name = NNS_G3dGetResNameByIdx(&srtAnm->dict, i);
			idx = NNS_G3dGetMatIdxByName(mat, name);
///			OS_Printf("i = %d::",i);
///			OS_Printf("idx = %d\n",idx);
		}
	}
#endif

	NNS_G3dRenderObjAddAnmObj( pRenderObj, pAnmData->AnmObjPtr );
}

//==============================================================================
/**
 * アニメのリムーブ（解放ではなく、モデリングデータについているアニメを削除する）
 *
 * @param   pRenderObj	レンダーOBJ
 * @param	pAnmData	アニメデータ
 *
 * @retval  BOOL				TRUE:リムーブした	FALSE:リムーブしなかった
 */
//==============================================================================
BOOL G3dAnimeData_Remove(NNSG3dRenderObj *pRenderObj, G3D_ANM_DATA_PTR pAnmData)
{
	if (pAnmData == NULL){
		return FALSE;
	}
	if (pAnmData->AnmObjPtr == NULL){
		return FALSE;
	}
	if (pRenderObj == NULL){
		return FALSE;
	}

	if ( (pRenderObj->anmMat == NULL)&&
		 (pRenderObj->anmJnt == NULL)&&
		 (pRenderObj->anmVis == NULL) ){
		return FALSE;
	}

	//現行では、リムーブする対象が無くてもこの関数を通す(その場合、内部ではリムーブせずに戻る)。
	//↑金銀で変更。上条件で、対象がない場合はこの関数を通さない
	NNS_G3dRenderObjRemoveAnmObj( pRenderObj, pAnmData->AnmObjPtr );
	return TRUE;

}

//==============================================================================
/**
 * 最大ループ数取得
 *
 * @param   pAnmData		アニメデータ
 *
 * @retval  u16 ループ数
 */
//==============================================================================
u16 G3dAnimeData_GetLoopMax(G3D_ANM_DATA_PTR pAnmData)
{
	return pAnmData->LoopMax;
}

//==============================================================================
/**
 * ストップフラグの切り替え
 *
 * @param	pAnmData				アニメデータポインタ
 * @param	inFlg					ストップフラグ
 *
 * @return	none
 */
//==============================================================================
void G3dAnimeData_SetStopFlg(G3D_ANM_DATA_PTR pAnmData, const BOOL inFlg)
{
	pAnmData->Stop = inFlg;
}

//==============================================================================
/**
 * アニメーションステートを動作中にする
 *
 * @param	inAnimePtr				アニメデータポインタ
 *
 * @return	none
 */
//==============================================================================
void G3dAnimeData_MoveAnime(G3D_ANM_DATA_PTR pAnmData)
{
	pAnmData->State = STATE_MOVE;
}

//==============================================================================
/**
 * アニメーションが終了しているかを返す
 * @param	inAnmData	アニメデータへのポインタ
 *
 * @return	BOOL	TRUE:終了　FALSE:NO 継続
 */
//==============================================================================
BOOL G3dAnimeData_IsAnimeEnd(G3D_ANM_DATA_PTR pAnmData)
{
	if (pAnmData->State == STATE_END){
		return TRUE;
	}else{
		return FALSE;
	}
}

//==============================================================================
/**
 * 終了アニメーションフレームセット
 *
 * @param	pAnmData	アニメーションデータへのポインタ
 *
 * @return	none
 */
//==============================================================================
void G3dAnimeData_SetLastFrame(G3D_ANM_DATA_PTR pAnmData)
{
	if (!pAnmData->Reverse){	//通常まわし
		pAnmData->AnmObjPtr->frame = NNS_G3dAnmObjGetNumFrame(pAnmData->AnmObjPtr)-(FX32_ONE);
	}else{						//逆まわし
		pAnmData->AnmObjPtr->frame = 0;
	}
}

//==============================================================================
/**
 * 指定アニメーションの再生方向を逆にする
 *
 * @param	pAnmData	アニメーションデータへのポインタ
 *
 * @return	none
 */
//==============================================================================
void G3dAnimeData_SetAnimeReverse(G3D_ANM_DATA_PTR pAnmData)
{
	if (pAnmData->Reverse){
		pAnmData->Reverse = FALSE;
	}else{
		pAnmData->Reverse = TRUE;
	}
}

//==============================================================================
/**
 * 指定アニメーションの再生方向を逆にする(直接指定)
 *
 * @param	pAnmData	アニメーションデータへのポインタ
 * @param	inReverse	逆再フラグ
 *
 * @return	none
 */
//==============================================================================
void G3dAnimeData_SetAnimeReverseDirect(G3D_ANM_DATA_PTR pAnmData, const BOOL inReverse)
{
	pAnmData->Reverse = inReverse;
}

//==============================================================================
/**
 * 指定アニメーションの最大ループ数をセット
 *
 * @param	pAnmData	アニメーションデータへのポインタ
 * @param	inLoopMax		ループ数
 *
 * @return	none
 */
//==============================================================================
void G3dAnimeData_SetAnimeLoopMax(G3D_ANM_DATA_PTR pAnmData, const int inLoopMax)
{
	pAnmData->LoopMax = inLoopMax;
}


//==============================================================================
/**
 * 開始アニメーションフレーム変更
 *
 * @param	outAnimeData	アニメーションデータへのポインタ
 *
 * @return	none
 */
//==============================================================================
static void ChangeFrame(G3D_ANM_DATA_PTR	outAnimeData)
{
	if (!outAnimeData->Reverse){	//通常まわし
		outAnimeData->AnmObjPtr->frame += (FX32_ONE);
		if (outAnimeData->AnmObjPtr->frame == NNS_G3dAnmObjGetNumFrame(outAnimeData->AnmObjPtr)){
#ifdef	DEBUG_ONLY_FOR_saitou
			//OS_Printf("1ループ終了::%d\n",outAnimeData->AnmObjPtr->frame);
#endif
			outAnimeData->AnmObjPtr->frame = 0;
		}

	}else{						//逆まわし
		if (outAnimeData->AnmObjPtr->frame <= 0){
			outAnimeData->AnmObjPtr->frame =
				NNS_G3dAnmObjGetNumFrame(outAnimeData->AnmObjPtr)-(FX32_ONE);
		}else{
			outAnimeData->AnmObjPtr->frame -= (FX32_ONE);
		}
	}
}

//==============================================================================
/**
 * アニメーションが最終フレームかを返す
 *
 * @param	inAnimeData	アニメーションデータへのポインタ
 *
 * @return	BOOL TRUE:最終フレーム	FALSE:最終フレーム以外
 */
//==============================================================================
static BOOL IsLastFrame(G3D_ANM_DATA_PTR	inAnimeData)
{
	BOOL rc;
	if (!inAnimeData->Reverse){	//通常まわし
		if (inAnimeData->AnmObjPtr->frame >=
				NNS_G3dAnmObjGetNumFrame(inAnimeData->AnmObjPtr)-(FX32_ONE)){
			rc = TRUE;
		}else{
			rc = FALSE;
		}
	}else{						//逆まわし
		if (inAnimeData->AnmObjPtr->frame == 0){
			rc = TRUE;
		}else{
			rc = FALSE;
		}
	}
	return rc;
}
